package org.finesys.codegen.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

import org.anyline.metadata.Column;
import org.anyline.metadata.Table;
import org.anyline.proxy.CacheProxy;
import org.anyline.proxy.ServiceProxy;
import org.finesys.codegen.conveter.GenTableConvert;
import org.finesys.codegen.dto.ColumnDTO;
import org.finesys.codegen.dto.GenTableGroupDTO;
import org.finesys.codegen.dto.TableDTO;
import org.finesys.codegen.entity.GenTable;
import org.finesys.codegen.entity.GenTableColumn;
import org.finesys.codegen.entity.GenTableGroup;
import org.finesys.codegen.enums.AutoFilledEnum;
import org.finesys.codegen.enums.BooleanFilledEnum;
import org.finesys.codegen.enums.CommonColumnFiledEnum;
import org.finesys.codegen.mapper.GenGroupMapper;
import org.finesys.codegen.mapper.GenTableMapper;
import org.finesys.codegen.properties.CodeGenDefaultProperties;
import org.finesys.codegen.service.GenTableColumnService;
import org.finesys.codegen.service.GenTableGroupService;
import org.finesys.codegen.service.GenTableService;
import org.finesys.common.mp.core.service.impl.BaseServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class GenTableServiceImpl extends BaseServiceImpl<GenTableMapper, GenTable> implements GenTableService {

    private final CodeGenDefaultProperties codeGenDefaultProperties;
    private final GenTableColumnService genTableColumnService;
    private final GenTableGroupService genTableGroupService;
    private final GenGroupMapper genGroupMapper;

    @Override
    public boolean saveTable(GenTableGroupDTO genTableGroupDTO) {
        GenTable genTable = GenTableConvert.INSTANCE.convert(genTableGroupDTO);
        this.save(genTable);
        //表单ID
        Long tableId = genTable.getTableId();
        //清除样式选择
        if (!ObjectUtils.isEmpty(genTableGroupDTO.getGroupIds())) {
            List<GenTableGroup> tableGroupList = genTableGroupDTO.getGroupIds().stream().map(groupId -> {
                GenTableGroup genTableGroup = new GenTableGroup();
                genTableGroup.setGroupId(groupId);
                genTableGroup.setTableId(tableId);
                return genTableGroup;
            }).collect(Collectors.toList());
            genTableGroupService.saveBatch(tableGroupList);
        }
        return true;
    }

    @Override
    public boolean updateTable(GenTableGroupDTO genTableGroupDTO) {
        GenTable genTable = GenTableConvert.INSTANCE.convert(genTableGroupDTO);
        this.updateById(genTable);
        //表单ID
        Long tableId = genTable.getTableId();
        //清除原来的样式
        genTableGroupService.remove(Wrappers.<GenTableGroup>lambdaQuery().eq(GenTableGroup::getTableId, genTable.getTableId()));
        //更新样式选择
        if (!ObjectUtils.isEmpty(genTableGroupDTO.getGroupIds())) {
            List<GenTableGroup> tableGroupList = genTableGroupDTO.getGroupIds().stream().map(groupId -> {
                GenTableGroup genTableGroup = new GenTableGroup();
                genTableGroup.setGroupId(groupId);
                genTableGroup.setTableId(tableId);
                return genTableGroup;
            }).collect(Collectors.toList());
            genTableGroupService.saveBatch(tableGroupList);
        }
        return true;
    }


    @Override
    public boolean removeTableByIds(Long[] ids) {
        //删除表
        baseMapper.deleteBatchIds(Arrays.asList(ids));
        //删除级联样式表
        Arrays.asList(ids).stream().forEach(tableId -> {
            genTableGroupService.remove(Wrappers.<GenTableGroup>lambdaQuery().eq(GenTableGroup::getTableId, tableId));
        });
        return true;
    }

    @Override
    public Page<TableDTO> queryDsTablePage(Page<TableDTO> page, TableDTO genTable) {
        String dsName = genTable.getDsName();
        if (!StringUtils.hasText(dsName)) {
            dsName = "master";
        }
        DynamicDataSourceContextHolder.push(dsName);
        //清除缓存
        CacheProxy.clear();
        //查询数据
        List<Table> tableList = ServiceProxy.metadata().tables().values().stream().collect(Collectors.toList());
        //总条数
        int total = tableList.size();
        //存在查询条件
        if (StringUtils.hasText(genTable.getTableName())) {
            tableList = tableList.stream().filter(table -> {
                return StrUtil.containsIgnoreCase(table.getName(false), genTable.getTableName());
            }).collect(Collectors.toList());
        }
        //分页参数，避免为空时报错
        int current = 1;
        int size = 10;
        if (page != null) {
            current = (int) page.getCurrent();
            size = (int) page.getSize();
        } else {
            page = new Page<>(1, 10);
        }
        // 根据 page 进行分页
        List<Table> pageList = CollUtil.page(current - 1, size, tableList);
        List<TableDTO> records = new ArrayList<>(pageList.stream().map(this::buildTableDto).collect(Collectors.toList()));
        page.setRecords(records);
        page.setTotal(total);
        return page;
    }

    /**
     * 转换成表对象信息
     */
    private TableDTO buildTableDto(Table table) {
        TableDTO tableDTO = new TableDTO();
        tableDTO.setTableName(table.getName());
        tableDTO.setTableComment(table.getComment());
        return tableDTO;
    }

    @Override
    public List<TableDTO> queryDsTableList(TableDTO tableDTO) {
        String dsName = tableDTO.getDsName();
        if (!StringUtils.hasText(dsName)) {
            dsName = "master";
        }
        DynamicDataSourceContextHolder.push(dsName);
        //清除缓存
        CacheProxy.clear();
        //查询数据
        String tableName = tableDTO.getTableName();
        if (StringUtils.hasText(tableName)) {
            return ServiceProxy.metadata().tables(tableName).values().stream().filter(s -> {
                return StrUtil.containsIgnoreCase(s.getName(), tableName);
            }).map(this::buildTableDto).collect(Collectors.toList());
        }
        //查询所有表
        return ServiceProxy.metadata().tables().values().stream().map(this::buildTableDto).collect(Collectors.toList());
    }

    @Override
    public Page<ColumnDTO> queryDsTableColumnPage(Page<ColumnDTO> page, ColumnDTO columnDTO) {
        String dsName = columnDTO.getDsName();
        if (!StringUtils.hasText(dsName)) {
            dsName = "master";
        }
        DynamicDataSourceContextHolder.push(dsName);
        //清除缓存
        CacheProxy.clear();
        //表名
        String tableName = columnDTO.getTableName();
        if (!StringUtils.hasText(tableName)) {
            return null;
        }
        //查询数据
        List<Column> columnList = ServiceProxy.metadata().table(tableName).columns();
        //查询数据
        //分页参数，避免为空时报错
        long current = 0;
        int size = 10;
        if (page != null) {
            current = page.getCurrent();
            size = (int) page.getSize();
        } else {
            page = new Page<>(1, 10);
        }
        // 根据 page 进行分页
        List<Column> pageList = CollUtil.page((int) current - 1, size, columnList);
        List<ColumnDTO> records = new ArrayList<>(pageList.stream().map(this::buildColumnDto).collect(Collectors.toList()));
        page.setRecords(records);
        page.setTotal(columnList.size());
        //查询所有表
        return page;
    }


    @Override
    public List<ColumnDTO> queryDsTableColumnList(String dsName, String tableName) {
        DynamicDataSourceContextHolder.push(dsName);
        //清除缓存
        CacheProxy.clear();
        //查询数据
        return ServiceProxy.metadata().columns(tableName).values().stream().map(this::buildColumnDto).collect(Collectors.toList());

    }

    private ColumnDTO buildColumnDto(Column column) {
        ColumnDTO columnDTO = new ColumnDTO();
        columnDTO.setColumnName(column.getName());
        columnDTO.setColumnComment(column.getComment());
        columnDTO.setColumnType(column.getOriginType());
        columnDTO.setJdbcType(column.getJdbcType());
        columnDTO.setColumnLength(column.getLength());
        columnDTO.setPrimaryKey(column.isPrimaryKey() == 1);

        return columnDTO;
    }

    @Override
    public String queryTableDdl(String dsName, String tableName) throws Exception {
        DynamicDataSourceContextHolder.push(dsName);
        //清除缓存
        CacheProxy.clear();
        //查询表结构
        Table table = ServiceProxy.metadata().table(tableName);
        //不执行sql
        table.execute(false);
        //创建语句
        ServiceProxy.ddl().create(table);
        //返回创建语句
        return table.getDdl();
    }

    @Override
    public GenTable queryOrBuildTable(String dsName, String tableName) {
        GenTable genTable = baseMapper.selectOne(Wrappers.<GenTable>lambdaQuery().eq(GenTable::getTableName, tableName).eq(GenTable::getDsName, dsName));
        //查询指定数据的表导入
        if (genTable == null) {
            genTable = this.tableImport(dsName, tableName);
        } else {
            //更新表字段信息
            genTable.setColumnList(genTableColumnService.list(Wrappers.<GenTableColumn>lambdaQuery().eq(GenTableColumn::getTableId, genTable.getTableId())));
            //更新子表信息
            if (StringUtils.hasText(genTable.getSubTableName())) {
                GenTable subGenTable = queryOrBuildTable(dsName, genTable.getSubTableName());
                genTable.setSubTable(subGenTable);
            }
            //获取组信息
            genTable.setGroupList(new ArrayList<>(genGroupMapper.findByTableId(genTable.getTableId())));
        }
        return genTable;
    }

    @Transactional(rollbackFor = Exception.class)
    private GenTable tableImport(String dsName, String tableName) {
        //手动切换数据源
        DynamicDataSourceContextHolder.push(dsName);
        //清空缓存数据
        CacheProxy.clear();
        //获取数据库表
        Table table = ServiceProxy.metadata().table(tableName);

        assert table != null;

        GenTable genTable = new GenTable();
        genTable.setTableName(tableName);
        genTable.setTableComment(table.getComment());
        genTable.setClassName(NamingCase.toPascalCase(tableName));
        genTable.setDsName(dsName);
        genTable.setBusinessName(table.getComment());
        genTable.setFunctionName(StrUtil.toCamelCase(tableName));
        //使用默认配置
        genTable.setVersion(codeGenDefaultProperties.getVersion());
        genTable.setPackageName(codeGenDefaultProperties.getPackageName());
        genTable.setModuleName(codeGenDefaultProperties.getModuleName());
        genTable.setFunctionAuthor(codeGenDefaultProperties.getAuthor());
        genTable.setEmail(codeGenDefaultProperties.getEmail());
        genTable.setBackendPath(codeGenDefaultProperties.getBackendPath());
        genTable.setFrontendPath(codeGenDefaultProperties.getFrontendPath());
        genTable.setGenWay(codeGenDefaultProperties.getGeneratorType());
        genTable.setTplCategory(codeGenDefaultProperties.getTplCategory());
        genTable.setTplType(codeGenDefaultProperties.getTplType());
        genTable.setOptions(codeGenDefaultProperties.getOptions());
        genTable.setFormCols(codeGenDefaultProperties.getFormCols());
        // 使用默认数据源
        DynamicDataSourceContextHolder.clear();
        //子表信息
        this.save(genTable);
        //列信息
        List<GenTableColumn> tableColumnList = getGenColumnList(table, genTable);
        //更新表字段信息，并存储
        genTableColumnService.initFieldList(tableColumnList);
        genTableColumnService.saveOrUpdateBatch(tableColumnList);
        genTable.setColumnList(tableColumnList);
        return genTable;
    }

    /**
     * 获取表列信息
     */
    private List<GenTableColumn> getGenColumnList(Table table, GenTable genTable) {
        LinkedHashMap<String, Column> columnLinkedHashMap = table.getColumns();
        List<GenTableColumn> genTableColumnList = new ArrayList<>();
        columnLinkedHashMap.forEach((columnName, column) -> {
            GenTableColumn genTableColumn = new GenTableColumn();
            genTableColumn.setTableId(genTable.getTableId());
            genTableColumn.setColumnName(columnName);
            genTableColumn.setColumnComment(column.getComment());
            genTableColumn.setColumnType(column.getTypeName());
            genTableColumn.setPrimaryPk(column.isPrimaryKey() == 1 ? BooleanFilledEnum.TRUE.getValue() : BooleanFilledEnum.FALSE.getValue());
            genTableColumn.setAutoFill(AutoFilledEnum.DEFAULT.name());
            genTableColumn.setFormItem(BooleanFilledEnum.TRUE.getValue());
            genTableColumn.setGridItem(BooleanFilledEnum.TRUE.getValue());
            genTableColumn.setFormRequired(BooleanFilledEnum.TRUE.getValue());
            //审计字段
            if (EnumUtil.contains(CommonColumnFiledEnum.class, columnName)) {
                CommonColumnFiledEnum commonColumnFiledEnum = CommonColumnFiledEnum.valueOf(columnName);
                genTableColumn.setAutoFill(commonColumnFiledEnum.getAutoFill());
                genTableColumn.setFormItem(commonColumnFiledEnum.getFormItem());
                genTableColumn.setGridItem(commonColumnFiledEnum.getGridItem());
                genTableColumn.setSort(commonColumnFiledEnum.getSort());
            }
            //设置主键信息
            if (BooleanFilledEnum.TRUE.getValue().equals(genTableColumn.getPrimaryPk())) {
                genTable.setPrimaryKeyColumn(genTableColumn);
            }
            genTableColumnList.add(genTableColumn);
        });
        return genTableColumnList;
    }
}
